package com.grm.util;

import com.grm.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class TreeUtils {
    private static final String ID_NAME = "id";
    private static final String PARENT_FIELD_NAME = "parentId";
    private static final String CHILDREN_FIELD_NAME = "children";

    /**
     * 把原始的list数据转换为tree结构
     *
     * @param originalList 原始数据
     * @param <T>          泛型
     * @return 树结构
     */
    public static <T> List<T> getTree(List<T> originalList) {
        // 1、找到根节点
        List<T> topList = new ArrayList<>();
        try {
            for (T t : originalList) {
                String parentIdValStr = BeanUtils.getProperty(t, PARENT_FIELD_NAME);
                Long parentId = Long.parseLong(parentIdValStr);
                if (parentId.equals(0L)) {
                    topList.add(t);
                }
            }
            // 2、将根节点从原始list中移除，减少处理次数
            originalList.removeAll(topList);
            // 3、递归调用，封装树结构
            fillTree(topList, originalList);
        } catch (Exception e) {
            throw new BusinessException("树结构转换异常：" + e.getMessage());
        }
        return topList;
    }

    /**
     * 递归调用封装树结构
     *
     * @param topList      根节点
     * @param originalList 原始数据
     * @param <T>          泛型
     */
    private static <T> void fillTree(List<T> topList, List<T> originalList) throws Exception {
        for (T t : topList) {
            // 1、获取子节点
            List<T> children = getChildren(t, originalList);
            if (children.isEmpty()) {
                continue;
            }
            // 2、在原始数据中移除子节点，减少遍历次数
            originalList.removeAll(children);
            // 3、递归调用fillTree()
            fillTree(children, originalList);
        }
    }

    /**
     * 获取子对象集合
     *
     * @param parent       父对象
     * @param originalList 原始数据
     * @param <T>          泛型
     * @return 子对象的集合
     */
    private static <T> List<T> getChildren(T parent, List<T> originalList) throws Exception {
        List<T> childList = new ArrayList<>();
        // 父节点的id
        Long id = Long.parseLong(BeanUtils.getProperty(parent, ID_NAME));
        for (T t : originalList) {
            // 子节点的parentId
            Long childParentId = Long.parseLong(BeanUtils.getProperty(t, PARENT_FIELD_NAME));
            if (id.equals(childParentId)) { // 找到了子节点
                childList.add(t);
            }
        }
        // 如果子节点有值，把子节点设置到父节点的children字段中
        if (!childList.isEmpty()) {
            FieldUtils.writeDeclaredField(parent, CHILDREN_FIELD_NAME, childList, true);
        }
        return childList;
    }
}
